using System;
using System.Globalization;
using System.IO;
using System.Text;
using CalcSharp.Core;
using CalcSharp.Core.Containers;
using CalcSharp.Core.IO;
using dnAnalytics.Math;
using System.Diagnostics;
using CalcSharp.Core.General;

namespace CalcSharp
{
    #region MiscFuncts
    sealed class MiscFuncts
    {
        private MiscFuncts() { }
        public static void calluserfunction(string[] cmdline, bool writeres)
        {
            StringBuilder s = new StringBuilder(Program.functionmem[cmdline[0].ToUpper(CultureInfo.CurrentCulture)].code);
            for (int i = 1; i < cmdline.Length; i++) Program.loaded.Mem["$" + i] = MiscFuncts.parsestr(cmdline[i]);
            s.Replace("  ", "");
            s.Replace("\t", "");
            MiscFuncts.RunBlock(s.ToString());
            if (writeres) Program.ConsoleForm.writeResults();
            for (int i = 1; i < cmdline.Length; i++) Program.loaded.Mem.unset("$" + i);

        }
        public static void RunBlock(string Block)
        {
            Program.result = new Tresult();
            string rep = Block.ToString().Replace("\r\n", "\n");
            string[] cmds = rep.Split('\n');
            int controll;
            foreach (string str in cmds)
            {
                if (str.Length != 0 && str != null)
                {
                    Program.cmds = MiscCoreFuncts.split(str, false);
                    controll = Program.analize(Program.cmds[0]);
                    Program.result = Program.callfunc(controll, true);
                    if (!double.IsNaN(Program.result.floatingpt)) Program.loaded.Mem["$lastres"] = Program.result.floatingpt;
                    else if (Program.result.matrixtype != null) Program.loaded.Mtrx_mem["#last_mtrx"] = Program.result.matrixtype;
                    else if (!Complex.IsNaN(Program.result.complex)) Program.loaded.CPLX_mem["&last_cplx"] = Program.result.complex;
                    else if (Program.result.settype != null) Program.loaded.Set_mem["@last_set"] = Program.result.settype;
                }
            }
        }
        public static string getstr(string s)
        {
            if (s.StartsWith("~")) return Program.loaded.String_mem["s"];
            else return s;
        }

        public static double parsestr(string s)
        {
            try
            {
                s = s.ToUpper(CultureInfo.CurrentCulture);
                string tmp;
                if (s.IndexOf('/') != -1)
                {
                    string[] t = s.Split('/');
                    return MiscFuncts.parsestr(t[0]) / MiscFuncts.parsestr(t[1]);
                }
                else if (s == "$PI") return 3.1415926535897932384626433832795;
                else if (s == "$E") return 2.7182818284590452353602874713527;
                else if (s.IndexOf("$") == 0) return Program.loaded.Mem[s];
                else if (Patterns.Match(s, Patterns.FloatArrayIndexer))
                {
                    string[] arr = s.Split('[');
                    if (arr.Length < 2) throw new CSException("Input error");
                    int index = Convert.ToInt32(MiscFuncts.parsestr(arr[1].Replace("]", "")));
                    ASet a = Program.loaded.Set_mem[arr[0]];
                    if (index - 1 > a.Count || index - 1 < 0) throw new CSException("Index out of range");
                    return a[index - 1];
                }
                else if (Patterns.Match(s, Patterns.MatrixIndexer))
                {
                    string[] arr = s.Split('[');
                    if (arr.Length < 2) throw new CSException("Input error");
                    string[] arr2 = arr[1].Split(';');
                    if (arr2.Length < 2) throw new CSException("Input error");
                    AMatrix a = Program.loaded.Mtrx_mem[arr[0]];
                    int i, j;
                    i = Convert.ToInt32(MiscFuncts.parsestr(arr2[0])) - 1;
                    if (i < 0 || i > a.Rows) throw new CSException("Row index out of range");
                    j = Convert.ToInt32(MiscFuncts.parsestr(arr2[1].Replace("]", ""))) - 1;
                    if (j < 0 || j > a.Columns) throw new CSException("Column index out of range");
                    return a[i, j];
                }
                else if (s.IndexOf("B") == s.Length - 1)
                {
                    tmp = s.Replace("B", @"");
                    return Convert.ToDouble(Converter.base2int64(2, tmp));
                }
                else if (s.ToUpper(CultureInfo.CurrentCulture).IndexOf("H") == s.Length - 1)
                {
                    tmp = s.Replace("H", @"");
                    return Convert.ToDouble(Converter.base2int64(16, tmp));
                }
                else if (s.IndexOf("O") == s.Length - 1)
                {
                    tmp = s.Replace("O", @"");
                    return Convert.ToDouble(Converter.base2int64(8, tmp));
                }
                else if (s.ToUpper(CultureInfo.CurrentCulture).IndexOf("HF") == s.Length - 1)
                {
                    tmp = s.Replace("HF", @"");
                    return Converter.hexa2float(tmp);
                }
                else if (s.ToUpper(CultureInfo.CurrentCulture).IndexOf("HD") == s.Length - 1)
                {
                    tmp = s.Replace("HD", @"");
                    return Converter.hexa2double(tmp);
                }
                else return Convert.ToDouble(s);
            }
            catch (Exception ex) 
            {
                if (ex is CSException) throw ex; 
                else throw new CSException("Can't parse " + s + " as a number"); 
            }
        }
        public static string echo()
        {
            int i;
            StringBuilder res = new StringBuilder();
            if (Program.cmds.Length == 2 && Program.loaded.Set_mem.isset(Program.cmds[1]))
            {
                /*foreach (double it in Program.loaded.Set_mem[Program.cmds[1]])
                {
                    if (((it - Math.Truncate(it)) == 0) && it > 31) res.Append(Convert.ToChar((int)it));
                    else res.Append(it+"; ");
                }*/
            }
            else
            {
                for (i = 1; i < Program.cmds.Length; i++)
                {
                    if (Program.cmds[i].ToUpper(CultureInfo.CurrentCulture) == "$PI") res.Append(Math.PI + " ");
                    else if (Program.cmds[i].ToUpper(CultureInfo.CurrentCulture) == "$E") res.Append(Math.E + " ");
                    else if (Program.cmds[i].IndexOf('$') == 0) res.Append(Program.loaded.Mem[Program.cmds[i]] + " ");
                    else res.Append(Program.cmds[i] + " ");
                }
            }
            return res.ToString();
        }
        public static CalculatorModes Changemod(string modestr)
        {
            if (modestr.ToUpper(CultureInfo.CurrentCulture) == "RAD") return CalculatorModes.Rad;
            else if (modestr.ToUpper(CultureInfo.CurrentCulture) == "DEG") return CalculatorModes.Deg;
            else if (modestr.ToUpper(CultureInfo.CurrentCulture) == "GRAD") return CalculatorModes.Grad;
            else if (modestr.ToUpper(CultureInfo.CurrentCulture) == "CPLX") return CalculatorModes.CPLX;
            else throw new CSException("Invalid mode");
        }
        public static currency.Currency ISOcode2Currenum(string isocode)
        {
            isocode = isocode.ToUpper(CultureInfo.CurrentCulture);
            if (isocode == "AFA") return currency.Currency.AFA;
            else if (isocode == "ALL") return currency.Currency.ALL;
            else if (isocode == "DZD") return currency.Currency.DZD;
            else if (isocode == "ARS") return currency.Currency.ARS;
            else if (isocode == "AWG") return currency.Currency.AWG;
            else if (isocode == "AUD") return currency.Currency.AUD;
            else if (isocode == "BSD") return currency.Currency.BSD;
            else if (isocode == "BHD") return currency.Currency.BHD;
            else if (isocode == "BDT") return currency.Currency.BDT;
            else if (isocode == "BBD") return currency.Currency.BBD;
            else if (isocode == "BZD") return currency.Currency.BZD;
            else if (isocode == "BMD") return currency.Currency.BMD;
            else if (isocode == "BTN") return currency.Currency.BTN;
            else if (isocode == "BOB") return currency.Currency.BOB;
            else if (isocode == "BWP") return currency.Currency.BWP;
            else if (isocode == "BRL") return currency.Currency.BRL;
            else if (isocode == "GBP") return currency.Currency.GBP;
            else if (isocode == "BND") return currency.Currency.BND;
            else if (isocode == "BIF") return currency.Currency.BIF;
            else if (isocode == "XOF") return currency.Currency.XOF;
            else if (isocode == "XAF") return currency.Currency.XAF;
            else if (isocode == "KHR") return currency.Currency.KHR;
            else if (isocode == "CAD") return currency.Currency.CAD;
            else if (isocode == "CVE") return currency.Currency.CVE;
            else if (isocode == "KYD") return currency.Currency.KYD;
            else if (isocode == "CLP") return currency.Currency.CLP;
            else if (isocode == "CNY") return currency.Currency.CNY;
            else if (isocode == "COP") return currency.Currency.COP;
            else if (isocode == "KMF") return currency.Currency.KMF;
            else if (isocode == "CRC") return currency.Currency.CRC;
            else if (isocode == "HRK") return currency.Currency.HRK;
            else if (isocode == "CUP") return currency.Currency.CUP;
            else if (isocode == "CYP") return currency.Currency.CYP;
            else if (isocode == "CZK") return currency.Currency.CZK;
            else if (isocode == "DKK") return currency.Currency.DKK;
            else if (isocode == "DJF") return currency.Currency.DJF;
            else if (isocode == "DOP") return currency.Currency.DOP;
            else if (isocode == "XCD") return currency.Currency.XCD;
            else if (isocode == "EGP") return currency.Currency.EGP;
            else if (isocode == "SVC") return currency.Currency.SVC;
            else if (isocode == "EEK") return currency.Currency.EEK;
            else if (isocode == "ETB") return currency.Currency.ETB;
            else if (isocode == "EUR") return currency.Currency.EUR;
            else if (isocode == "FKP") return currency.Currency.FKP;
            else if (isocode == "GMD") return currency.Currency.GMD;
            else if (isocode == "GHC") return currency.Currency.GHC;
            else if (isocode == "GIP") return currency.Currency.GIP;
            else if (isocode == "XAU") return currency.Currency.XAU;
            else if (isocode == "GTQ") return currency.Currency.GTQ;
            else if (isocode == "GNF") return currency.Currency.GNF;
            else if (isocode == "GYD") return currency.Currency.GYD;
            else if (isocode == "HTG") return currency.Currency.HTG;
            else if (isocode == "HNL") return currency.Currency.HNL;
            else if (isocode == "HKD") return currency.Currency.HKD;
            else if (isocode == "HUF") return currency.Currency.HUF;
            else if (isocode == "ISK") return currency.Currency.ISK;
            else if (isocode == "INR") return currency.Currency.INR;
            else if (isocode == "IDR") return currency.Currency.IDR;
            else if (isocode == "IQD") return currency.Currency.IQD;
            else if (isocode == "ILS") return currency.Currency.ILS;
            else if (isocode == "JMD") return currency.Currency.JMD;
            else if (isocode == "JPY") return currency.Currency.JPY;
            else if (isocode == "JOD") return currency.Currency.JOD;
            else if (isocode == "KZT") return currency.Currency.KZT;
            else if (isocode == "KES") return currency.Currency.KES;
            else if (isocode == "KRW") return currency.Currency.KRW;
            else if (isocode == "KWD") return currency.Currency.KWD;
            else if (isocode == "LAK") return currency.Currency.LAK;
            else if (isocode == "LVL") return currency.Currency.LVL;
            else if (isocode == "LBP") return currency.Currency.LBP;
            else if (isocode == "LSL") return currency.Currency.LSL;
            else if (isocode == "LRD") return currency.Currency.LRD;
            else if (isocode == "LYD") return currency.Currency.LYD;
            else if (isocode == "LTL") return currency.Currency.LTL;
            else if (isocode == "MOP") return currency.Currency.MOP;
            else if (isocode == "MKD") return currency.Currency.MKD;
            else if (isocode == "MGF") return currency.Currency.MGF;
            else if (isocode == "MWK") return currency.Currency.MWK;
            else if (isocode == "MYR") return currency.Currency.MYR;
            else if (isocode == "MVR") return currency.Currency.MVR;
            else if (isocode == "MTL") return currency.Currency.MTL;
            else if (isocode == "MRO") return currency.Currency.MRO;
            else if (isocode == "MUR") return currency.Currency.MUR;
            else if (isocode == "MXN") return currency.Currency.MXN;
            else if (isocode == "MDL") return currency.Currency.MDL;
            else if (isocode == "MNT") return currency.Currency.MNT;
            else if (isocode == "MAD") return currency.Currency.MAD;
            else if (isocode == "MZM") return currency.Currency.MZM;
            else if (isocode == "MMK") return currency.Currency.MMK;
            else if (isocode == "NAD") return currency.Currency.NAD;
            else if (isocode == "NPR") return currency.Currency.NPR;
            else if (isocode == "ANG") return currency.Currency.ANG;
            else if (isocode == "NZD") return currency.Currency.NZD;
            else if (isocode == "NIO") return currency.Currency.NIO;
            else if (isocode == "NGN") return currency.Currency.NGN;
            else if (isocode == "KPW") return currency.Currency.KPW;
            else if (isocode == "NOK") return currency.Currency.NOK;
            else if (isocode == "OMR") return currency.Currency.OMR;
            else if (isocode == "XPF") return currency.Currency.XPF;
            else if (isocode == "PKR") return currency.Currency.PKR;
            else if (isocode == "XPD") return currency.Currency.XPD;
            else if (isocode == "PAB") return currency.Currency.PAB;
            else if (isocode == "PGK") return currency.Currency.PGK;
            else if (isocode == "PYG") return currency.Currency.PYG;
            else if (isocode == "PEN") return currency.Currency.PEN;
            else if (isocode == "PHP") return currency.Currency.PHP;
            else if (isocode == "XPT") return currency.Currency.XPT;
            else if (isocode == "PLN") return currency.Currency.PLN;
            else if (isocode == "QAR") return currency.Currency.QAR;
            else if (isocode == "ROL") return currency.Currency.ROL;
            else if (isocode == "RUB") return currency.Currency.RUB;
            else if (isocode == "WST") return currency.Currency.WST;
            else if (isocode == "STD") return currency.Currency.STD;
            else if (isocode == "SAR") return currency.Currency.SAR;
            else if (isocode == "SCR") return currency.Currency.SCR;
            else if (isocode == "SLL") return currency.Currency.SLL;
            else if (isocode == "XAG") return currency.Currency.XAG;
            else if (isocode == "SGD") return currency.Currency.SGD;
            else if (isocode == "SKK") return currency.Currency.SKK;
            else if (isocode == "SIT") return currency.Currency.SIT;
            else if (isocode == "SBD") return currency.Currency.SBD;
            else if (isocode == "SOS") return currency.Currency.SOS;
            else if (isocode == "ZAR") return currency.Currency.ZAR;
            else if (isocode == "LKR") return currency.Currency.LKR;
            else if (isocode == "SHP") return currency.Currency.SHP;
            else if (isocode == "SDD") return currency.Currency.SDD;
            else if (isocode == "SRG") return currency.Currency.SRG;
            else if (isocode == "SZL") return currency.Currency.SZL;
            else if (isocode == "SEK") return currency.Currency.SEK;
            else if (isocode == "CHF") return currency.Currency.CHF;
            else if (isocode == "SYP") return currency.Currency.SYP;
            else if (isocode == "TWD") return currency.Currency.TWD;
            else if (isocode == "TZS") return currency.Currency.TZS;
            else if (isocode == "THB") return currency.Currency.THB;
            else if (isocode == "TOP") return currency.Currency.TOP;
            else if (isocode == "TTD") return currency.Currency.TTD;
            else if (isocode == "TND") return currency.Currency.TND;
            else if (isocode == "TRL") return currency.Currency.TRL;
            else if (isocode == "USD") return currency.Currency.USD;
            else if (isocode == "AED") return currency.Currency.AED;
            else if (isocode == "UGX") return currency.Currency.UGX;
            else if (isocode == "UAH") return currency.Currency.UAH;
            else if (isocode == "UYU") return currency.Currency.UYU;
            else if (isocode == "VUV") return currency.Currency.VUV;
            else if (isocode == "VEB") return currency.Currency.VEB;
            else if (isocode == "VND") return currency.Currency.VND;
            else if (isocode == "YER") return currency.Currency.YER;
            else if (isocode == "YUM") return currency.Currency.YUM;
            else if (isocode == "ZMK") return currency.Currency.ZMK;
            else if (isocode == "ZWD") return currency.Currency.ZWD;
            else if (isocode == "TRY") return currency.Currency.TRY;
            else throw new CSException("Invalid Currency Code: " + isocode);
        }
        public static double chartoUTFnum(char c)
        {
            return (double)c;
        }
        public static void Mount(string[] param)
        {
            if (Program.loaded.C_fs.isset(param[1])) throw new CSException(param[1] + " already mounted");
            string pass = null;
            if (param.Length > 2) pass = param[2];
            Program.loaded.C_fs[param[1]] = new CalcSharp.Core.IO.compfs(param[2], pass);
        }
        public static void UnMount(string fsname)
        {
            if (fsname.ToUpper() == "ALL") Program.loaded.C_fs.unsetAll();
            else
            {
                if (!Program.loaded.C_fs.isset(fsname)) throw new CSException(fsname + " not mounted");
                Program.loaded.C_fs[fsname].Unmount();
                Program.loaded.C_fs.unset(fsname);
            }
        }

        public static Stream MakeStream(string URL)
        {
            if (URL.StartsWith("*"))
            {
                MemoryStream S = new MemoryStream();
                string[] urlpar = URL.Split('/');
                string file = URL.Replace(urlpar[0] + @"/", "");
                Program.loaded.C_fs[urlpar[0]].Extractto(S, file.ToUpper());
                return S;
            }
            else return File.OpenRead(URL);
        }

        public static void Extract(string URL, string dest)
        {
            MemoryStream tmp = (MemoryStream)MiscFuncts.MakeStream(URL);
            tmp.Seek(0, SeekOrigin.Begin);
            FileStream outp = File.Create(dest);
            StreamHelper.Copy(tmp, outp);
            outp.Close();
        }
    }
    #endregion
}